Generación de modelos de predicción

En este notebook se utiliza el dataset procesado en el Análisis exploratorio de datos, cargando el archivo parquet en el clúster para entrenar con la técnica de regresión lineal y obtener un modelo predictivo de la temperatura en los próximos años.

Se usarán las utlidades de ML lib de pyspark para obtener los modelos para predecir la variación de temperatura promedio.

In [1]:
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('prediccionApp').getOrCreate()
sc = spark.sparkContext
In [2]:
# cargando dataset
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)

# cargando el dataset
ndf = sqlContext.read.parquet('hdfs:///datasets/ndf.parquet')
ndf.show(3)
+---+-------------------+------------------+-----------------------------+-----------+--------+--------+---------+---------+
| id|                 dt|AverageTemperature|AverageTemperatureUncertainty|       City| Country|Latitude|Longitude|Elevation|
+---+-------------------+------------------+-----------------------------+-----------+--------+--------+---------+---------+
|  1|1825-01-01 00:00:00|25.331999999999997|                        3.194|Johor Bahru|Malaysia|   0.80N|  103.66E|        0|
|  2|1825-02-01 00:00:00|25.549000000000003|           1.4709999999999999|Johor Bahru|Malaysia|   0.80N|  103.66E|        0|
|  3|1825-03-01 00:00:00|            26.285|                        2.193|Johor Bahru|Malaysia|   0.80N|  103.66E|        0|
+---+-------------------+------------------+-----------------------------+-----------+--------+--------+---------+---------+
only showing top 3 rows

In [3]:
# importando las bibliotecas
from pyspark.ml.regression import LinearRegression
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.feature import StandardScaler
from pyspark.ml import Pipeline
from pyspark.sql.functions import *

Regresión lineal

Se aplicarará regresión lineal para obtener un modelo que se ajuste a la función de temperatura promedio por años.

In [4]:
# para por año
from pyspark.sql.functions import udf
import pandas as pd
from pyspark.sql.types import ArrayType, StructField, StructType, StringType, IntegerType

def getYear(fecha):
    anyo = fecha.split("-")[0]
    return int(anyo)

getYear_udf = udf(getYear, IntegerType())
In [5]:
ndfa = ndf.withColumn('dt', getYear_udf(ndf["dt"]))
In [6]:
ndfa = ndfa.groupBy('dt').avg("AverageTemperature", "AverageTemperatureUncertainty")
In [7]:
ndfa.count()
Out[7]:
267
In [8]:
ndfa.columns
Out[8]:
['dt', 'avg(AverageTemperature)', 'avg(AverageTemperatureUncertainty)']

Regresión lineal simple

Regresión lineal simple para predecir la temperatura promedio a partir de las columnas años e incertidumbre de temperatura promedio.

In [9]:
# Probando la correlacion entre ambas variables
ndfa.stat.corr("avg(AverageTemperature)", "avg(AverageTemperatureUncertainty)")
Out[9]:
-0.8720850643534727

El valor de -0.8720850643534727 indica una considerable correlación negativa entre la temperatura promedio y el grado de incertidumbre de las muestras, esto quiere decir que a medida que aumenta la temperatura promedio se reduce el nivel de incertidumbre de las muestras.

In [10]:
ndfa.stat.corr("dt", "avg(AverageTemperature)")
Out[10]:
0.8625908201828391

El valor de 0.8625908201828391 indica una considerable correlación positiva entre los años y la temperatura promedio, esto indica que a medida que se incrementan los años también se incrementa de forma similar la temperatura promedio a nivel global.

Años y temperatura promedio

In [18]:
def pipelinePrediccionRegresionLineal(dataset, features, scale=False, \
                                      featuresColName="features", labelColName="avg(AverageTemperature)", \
                                      maxIter=10, regParam=.01, seed=19954, \
                                      returnDatasets=False):
    ''' Realizar todo el pipeline para el entrenamiento mediante regresion lineal, desde la división en
    training, test y las etapas del pipeline
    retorna el modelo de prediccion y las predicciones '''
    # creando dataframe para entrenamiento y test
    lr_data = dataset.select(*features, labelColName)
    (training, test) = lr_data.randomSplit([.7, .3], seed=seed)
    
    # armando el pipeline
    vectorAssembler = None
    standardScaler = None
    stages = []
    if (scale):
        vectorAssembler = VectorAssembler(inputCols=features, outputCol="unscaled_features")
        standardScaler = StandardScaler(inputCol="unscaled_features", output=featuresColName)
        lr = LinearRegression(featuresCol=featuresColName, labelCol=labelColName, maxIter=maxIter, regParam=regParam)
        stages = [vectorAssembler, standardScaler, lr]
    else:
        vectorAssembler = VectorAssembler(inputCols=features, outputCol=featuresColName)
        lr = LinearRegression(featuresCol=featuresColName, labelCol=labelColName, maxIter=maxIter, regParam=regParam)
        stages = [vectorAssembler, lr]
    pipeline = Pipeline(stages=stages)
    
    # ejecucion del pipeline
    model = pipeline.fit(training)
    prediction = model.transform(test)
    if returnDatasets:
        return (model, prediction, training, test)
    return (model, prediction)
In [22]:
model1, predictions1 = pipelinePrediccionRegresionLineal(ndfa, features=["dt"])
In [23]:
predictions1.show(10)
+----+-----------------------+--------+------------------+
|  dt|avg(AverageTemperature)|features|        prediction|
+----+-----------------------+--------+------------------+
|1829|     13.971163343064703|[1829.0]|13.459330320223359|
|1884|     16.767088266037913|[1884.0]|15.491084049388931|
|1975|     17.872018209876778|[1975.0]|18.852712946735593|
|1808|       9.24038807458366|[1808.0]|12.683569805451057|
|1863|      15.04401686324851|[1863.0]|14.715323534616616|
|1924|     17.440732359924557|[1924.0]|  16.9687231251457|
|2007|     18.686940598290295|[2007.0]|20.034824207341018|
|1752|     4.2530635838149635|[1752.0]|10.614875099391568|
|1826|     15.007845728770544|[1826.0]| 13.34850738954161|
|1816|     14.266152702062199|[1816.0]|12.979097620602403|
+----+-----------------------+--------+------------------+
only showing top 10 rows

In [24]:
# Obteniendo la fórmula de regresión lineal
modelo = model1.stages[-1]
print("Coefficients: %s" % str(modelo.coefficients))
print("Intercept: %s" % str(modelo.intercept))
#print(modelo.coefficients)
𝛼1 = modelo.intercept
𝛽1 = modelo.coefficients[0]
Coefficients: [0.03694097689391944]
Intercept: -54.10571641875529

Considerando la ecuación de regresión lineal y los coeficientes obtenidos:

$ y = \alpha + \beta x_i \\ y = 0.0369 - 54.10571 x_i $

Se puede usar esta formula para generar predicciones de temperatura promedio para los siguientes años.

In [25]:
# obteniendo predicciones de 1800 a 2050
#predicciones = [print (str(i), 𝛼1 + 𝛽1*i) for i in range(1800,2051)]

def simpleLrPredictionsByYears(intercept, coeff, ini=1900, fin=2051):
    predicciones = []
    for i in range(1800, 2051):
        predicciones.append([i, intercept + i*coeff])
    return predicciones

df_predictions1 = pd.DataFrame(data=simpleLrPredictionsByYears(𝛼1, 𝛽1), columns=["dt", "AverageTemperature"])
df_predictions1.head()
Out[25]:
dt AverageTemperature
0 1800 12.388042
1 1801 12.424983
2 1802 12.461924
3 1803 12.498865
4 1804 12.535806
In [26]:
import plotly
import plotly.graph_objs as go
import pandas as pd
import numpy as np
from plotly.offline import init_notebook_mode, iplot

init_notebook_mode(connected=True)         # initiate notebook for offline plot
In [27]:
df_years = ndfa.toPandas()
df_years = df_years.sort_values(by="dt")
In [28]:
years = df_years["dt"].values
In [29]:
data = [go.Scatter(
            x=df_years["dt"],
            y=df_years['avg(AverageTemperature)'],
            name="Valor real", mode="markers"),
        go.Scatter(
            x=df_predictions1["dt"],
            y=df_predictions1['AverageTemperature'],
        name="Predicción 1")
       ]

plotly.offline.iplot({
    "data": data,
    "layout": go.Layout(title="Predicción de temperatura Promedio Global por año (C°)")
})

La línea es el modelo lineal de predicción que se obtiene resultado del entrenamiento con regresión lineal simple entre los años y la temperatura promedio a nivel global, esta muestra que para el año 2050 la temperatura promedio global sería de 21.58 °C.

In [39]:
# evaluaciones segun distintos metodos de evaluación
from pyspark.ml.evaluation import RegressionEvaluator

def generalEvaluation(prediction, labelCol, predictionCol):
    eval = RegressionEvaluator(labelCol=labelCol, predictionCol=predictionCol, metricName="rmse")
    # Root Mean Square Error
    rmse = eval.evaluate(prediction)
    print("RMSE: %.3f" % rmse)
    # Mean Square Error
    mse = eval.evaluate(prediction, {eval.metricName: "mse"})
    print("MSE: %.3f" % mse)

    # Mean Absolute Error
    mae = eval.evaluate(prediction, {eval.metricName: "mae"})
    print("MAE: %.3f" % mae)

    # r2 - coefficient of determination
    r2 = eval.evaluate(prediction, {eval.metricName: "r2"})
    print("r2: %.3f" %r2)
In [33]:
generalEvaluation(predictions1, labelCol="avg(AverageTemperature)", predictionCol="prediction")
RMSE: 1.576
MSE: 2.483
MAE: 1.295
r2: 0.773

Conclusión primer modelo: El modelo de regresión lineal a partir de la temperatura promedio y los años tiene un coeficiente de determinación de 0.773 lo que muestra un ajuste cercano al comportamiento real, sin embargo es necesario considerar más columnas usando técnicas de regresión lineal múltiple.

También hay que notar que entre los años 1750 y 1850 aproximandamente las muestras de promedio de temperatura global son muy dispersas y modifican el resultado del entrenamiento, a continuación se procederá a entrenar con la misma técnica pero sin tomar en cuenta este rango de fechas con valores muy dispersos.

In [34]:
ndfa1 = ndfa.filter(ndfa.dt.between(1850, 2016))
ndfa1.count()
Out[34]:
164
In [49]:
model2, predictions = pipelinePrediccionRegresionLineal(ndfa1, ["dt"], scale=False, \
                            featuresColName="features", labelColName="avg(AverageTemperature)")
In [50]:
generalEvaluation(predictions, labelCol="avg(AverageTemperature)", predictionCol="prediction")
RMSE: 0.350
MSE: 0.123
MAE: 0.235
r2: 0.749

Se muestra un coeficiente de determinación r2 de 0.749 lo que muestra un ajuste aceptable de la línea de predicción con los datos reales, con este modelo se pueden hacer predicciones.

In [51]:
# Obteniendo la fórmula de regresión lineal
modelo = model2.stages[-1]
print("Coefficients: %s" % str(modelo.coefficients))
print("Intercept: %s" % str(modelo.intercept))
𝛼2 = modelo.intercept
𝛽2 = modelo.coefficients[0]
Coefficients: [0.012792554487012674]
Intercept: -7.211800756996922

Considerando la ecuación de regresión lineal y los coeficientes obtenidos, se tiene la fórmula de predicción:

$ y = \alpha + \beta x_i \\ y = -7.2118 + 0.012 x_i $

In [52]:
df_predictions2 = pd.DataFrame(data=simpleLrPredictionsByYears(𝛼2, 𝛽2), columns=["dt", "AverageTemperature"])
In [53]:
data = [go.Scatter(
            x=df_years["dt"],
            y=df_years['avg(AverageTemperature)'],
            name="Valor real", mode="markers"),
        go.Scatter(
            x=df_predictions2["dt"],
            y=df_predictions2['AverageTemperature'],
        name="Predicción 2")
       ]

plotly.offline.iplot({
    "data": data,
    "layout": go.Layout(title="Predicción de temperatura Promedio Global por año (C°)")
})

Conclusión modelo 2: El segundo modelo de regresión lineal tomando en cuenta solo datos desde 1850 tiene resultados mejor ajustados a la variable temperatura promedio y como se observa en la gráfica predice que para el año 2050 la temperatura promedio global será de 19.01 °C.

Regresión lineal múltiple

Ahora se usarán varias variables para generar modelos lineales, entre ellas temperatura promedio, elevación en metros sobre el nivel del mar e incertidumbre de las muestras de temperatura promedio.

In [54]:
# agrupando datos por altitud en metros sobre le nivel del mar
ndfe = ndf.withColumn('dt', getYear_udf(ndf["dt"]))
# solo tomando en cuenta desde 1850
ndfe.filter(ndfe.dt.between(1850, 2016))
ndfe = ndfe.groupBy('Elevation').avg("AverageTemperature", "AverageTemperatureUncertainty")
In [55]:
print(ndfe.count())
ndfe.show(5)
692
+---------+-----------------------+----------------------------------+
|Elevation|avg(AverageTemperature)|avg(AverageTemperatureUncertainty)|
+---------+-----------------------+----------------------------------+
|     1342|     24.001515877771144|                0.9285710005991603|
|     2122|     14.722361797752791|                0.8721698876404473|
|      148|      3.494045401875064|                 1.516418518908674|
|      737|      21.66334247247743|                0.8451108617909049|
|      540|     14.550836621143173|                0.7755063227111787|
+---------+-----------------------+----------------------------------+
only showing top 5 rows

In [56]:
# examinando correlacion de variables
print("Correlacion Elevacion y temperatura promedio:", ndfe.stat.corr("Elevation", "avg(AverageTemperature)"))
print("Correlacion incertidumbre temperautra y temperatura promedio:", \
      ndfe.stat.corr("avg(AverageTemperatureUncertainty)", "avg(AverageTemperature)"))           
Correlacion Elevacion y temperatura promedio: -0.18741872743333104
Correlacion incertidumbre temperautra y temperatura promedio: -0.5854335439830737

Existe una baja correlación entre la temperatura promedio elevación de las ciudades (msnm) por lo que no se podría obtener buenos modelos de predicción de temperatura promedio agrupada por elevación (altitud) de ciudades.

Modelos de predicción por altitud de ciudades

Trataremos de probar que mientras a mayor altitud se encuentra una ciudad, mayor incremento de temperatura tendrá en el tiempo usando regresión lineal.

Formulación de la hipótesis

  • H0: Mientras a más altitud se encuentre una ciudad mayor es el incremento de temperatura en el tiempo.

Usando la regresión lineal y haciendo proeycciones en el tiempo traduciremos esta hipótesis en:

  • $m_{m}$ = Pendiente de la recta de regresión lineal para ciudades con menor altitud.
  • $m_{M}$ = Pendiente de la recta de regresión lineal para ciudades con mayor altitud.

Y:

  • Si $m_{m}$ < $m_{M}$ entonces se cumple H0.

Tratamiento de datos

Vamos a agrupar el conjunto de datos por elevación y años, pero como existen muchas elevaciones y cientos de años que analizar, no se puede resumir la elevación ya que este es un dato en cierta forma categórico.

Se tiene una elevación por cada ciudad y para hacer un análisis aproximado, se tomarán en cuenta las 20 ciudades con mayor altitud y las 20 ciudades con menos altitud, esto nos permitirá agrupar por altitudes extremas y obtener series de variación de temperatura por años. Luego a estas agrupaciones se les puede aplicar regresión lineal.

In [57]:
# agrupando datos por elevación en metros sobre le nivel del marq
ndfe = ndf.withColumn('dt', getYear_udf(ndf["dt"]))
# solo tomando en cuenta desde 1850
ndfe = ndfe.filter(ndfe.dt.between(1850, 2016))
ndfe = ndfe.groupBy('dt', 'Elevation').avg("AverageTemperature", "AverageTemperatureUncertainty")
# agrupando por años y altitud
ndfe.count()
Out[57]:
111857
In [58]:
# ordenando por altitud
ndfe = ndfe.orderBy(["Elevation"])
ndfe.show(5)
+----+---------+-----------------------+----------------------------------+
|  dt|Elevation|avg(AverageTemperature)|avg(AverageTemperatureUncertainty)|
+----+---------+-----------------------+----------------------------------+
|2008|      -29|     11.783583333333334|               0.47066666666666673|
|1884|      -29|      9.989500000000001|                0.9835000000000002|
|1876|      -29|                10.4095|                1.6505833333333335|
|1880|      -29|      9.206583333333333|                1.2377500000000001|
|1921|      -29|      9.871333333333332|                0.7344166666666666|
+----+---------+-----------------------+----------------------------------+
only showing top 5 rows

In [59]:
# obteniendo las altitudes extremas
elevaciones = ndfe.groupBy("Elevation").avg("avg(AverageTemperature)").select("Elevation").collect()
In [60]:
from pyspark.sql.functions import lit
from pyspark.sql.functions import udf

#udf(lambda z: timestampsToString(z), StringType())

menores20 = [x[0] for x in elevaciones[:20]]
mayores20 = [x[0] for x in elevaciones[-20:]]
mayores20 = sorted(mayores20, reverse=True)
print("20 menores:", menores20)
print("20 mayores:", mayores20)

# mayores 20
ndfeM = ndfe.filter(ndfe["Elevation"] == mayores20[0])
for elevation in mayores20[1:]:
    dftmp = ndfe.filter(ndfe["Elevation"]== elevation)
    dftmp = dftmp.groupBy("dt").avg("avg(AverageTemperature)", "avg(AverageTemperatureUncertainty)")
    dftmp = dftmp.withColumnRenamed("avg(avg(AverageTemperature))","avg(AverageTemperature)")
    dftmp = dftmp.withColumn("Elevation", lit(elevation).cast(IntegerType()))
    dftmp = dftmp.withColumnRenamed("avg(avg(AverageTemperatureUncertainty))", \
                                    "avg(AverageTemperatureUncertainty)")
    dftmp = dftmp.select("dt", "Elevation", "avg(AverageTemperature)", "avg(AverageTemperatureUncertainty)")
    ndfeM = ndfeM.union(dftmp)
#ndfeM = ndfeM.orderBy(["Elevation"])
print(ndfeM.count())

# menores 20
ndfem = ndfe.filter(ndfe["Elevation"] == menores20[0])
for elevation in menores20[1:]:
    dftmp = ndfe.filter(ndfe["Elevation"]== elevation)
    dftmp = dftmp.groupBy("dt").avg("avg(AverageTemperature)", "avg(AverageTemperatureUncertainty)")
    dftmp = dftmp.withColumnRenamed("avg(avg(AverageTemperature))","avg(AverageTemperature)")
    dftmp = dftmp.withColumn("Elevation", lit(elevation).cast(IntegerType()))
    dftmp = dftmp.withColumnRenamed("avg(avg(AverageTemperatureUncertainty))", \
                                    "avg(AverageTemperatureUncertainty)")
    dftmp = dftmp.select("dt", "Elevation", "avg(AverageTemperature)", "avg(AverageTemperatureUncertainty)")
    ndfem = ndfem.union(dftmp)
print(ndfem.count())
20 menores: [-29, -27, -26, -3, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
20 mayores: [5155, 4615, 4532, 4286, 4270, 4240, 4088, 4044, 4043, 4007, 3957, 3951, 3921, 3896, 3759, 3471, 3307, 3216, 3155, 3093]
3076
3280
In [61]:
ndfeM.filter(ndfeM.dt==1992).show(5)
ndfem.filter(ndfem.dt==1992).show(5)
+----+---------+-----------------------+----------------------------------+
|  dt|Elevation|avg(AverageTemperature)|avg(AverageTemperatureUncertainty)|
+----+---------+-----------------------+----------------------------------+
|1992|     5155|    -1.1489166666666664|                             0.444|
|1992|     4615|                5.60175|                0.5471666666666667|
|1992|     4532|                10.8645|                0.5573333333333333|
|1992|     4286|      8.420583333333333|                0.6349166666666667|
|1992|     4270|     11.665333333333335|                0.8322500000000002|
+----+---------+-----------------------+----------------------------------+
only showing top 5 rows

+----+---------+-----------------------+----------------------------------+
|  dt|Elevation|avg(AverageTemperature)|avg(AverageTemperatureUncertainty)|
+----+---------+-----------------------+----------------------------------+
|1992|      -29|     10.281999999999998|                            0.4215|
|1992|      -27|                 10.191|               0.33533333333333326|
|1992|      -26|      8.550916666666668|                0.3854166666666667|
|1992|       -3|      9.839583333333334|                0.2889999999999999|
|1992|       -1|     11.136060606060607|                0.2862234848484851|
+----+---------+-----------------------+----------------------------------+
only showing top 5 rows

Ahora agruparemos en dos grandes grupos de temperatura según altitudes bajas y altas.

In [62]:
ndfeM = ndfeM.groupBy("dt").avg("avg(AverageTemperature)", "avg(AverageTemperatureUncertainty)")
In [63]:
ndfem = ndfem.groupBy("dt").avg("avg(AverageTemperature)", "avg(AverageTemperatureUncertainty)")
In [64]:
ndfeM = ndfeM.withColumnRenamed("avg(avg(AverageTemperature))", "avg(AverageTemperature)")
ndfeM = ndfeM.withColumnRenamed("avg(avg(AverageTemperatureUncertainty))", "avg(AverageTemperatureUncertainty)")
ndfem = ndfem.withColumnRenamed("avg(avg(AverageTemperature))", "avg(AverageTemperature)")
ndfem = ndfem.withColumnRenamed("avg(avg(AverageTemperatureUncertainty))", "avg(AverageTemperatureUncertainty)")

Entrenamiento 20 ciudades con mayor altitud

In [65]:
model3, predictions = pipelinePrediccionRegresionLineal(ndfeM,\
                            features=["dt", "avg(AverageTemperatureUncertainty)"], \
                            featuresColName="features", labelColName="avg(AverageTemperature)")
In [66]:
generalEvaluation(predictions, labelCol="avg(AverageTemperature)", predictionCol="prediction")
RMSE: 0.312
MSE: 0.097
MAE: 0.231
r2: 0.674

El modelo predictivo resulta en un r2 de 0.646 que es un acercamiento que se puede aprovechar para hacer predicciones.

In [69]:
# Obteniendo la fórmula de regresión lineal
modelo = model3.stages[-1]
print("params", modelo)
print("Coefficients: %s" % str(modelo.coefficients))
print("Intercept: %s" % str(modelo.intercept))
𝛼3 = modelo.intercept
𝛽3_1 = modelo.coefficients[0]
𝛽3_2 = modelo.coefficients[1]
params LinearRegression_dc411c70f3e1
Coefficients: [0.008813582768108213,-0.2874945103427946]
Intercept: -8.038079680590089

$ y = \alpha + \beta X_i \\ Donde: \beta = [0.0091,-0.2621]; X = [[x_{1,1},x_{1,2}], ... ,[x_{i,1},x_{i,2}]] \\ y = -8.6714 + 0.0091 X_1 + (-0.2622) X_2 $

Entrenamiento 20 ciudades con menor altitud

In [77]:
model4, predictions = pipelinePrediccionRegresionLineal(ndfem,\
                            features=["dt", "avg(AverageTemperatureUncertainty)"], \
                            featuresColName="features", labelColName="avg(AverageTemperature)")
In [78]:
generalEvaluation(predictions, labelCol="avg(AverageTemperature)", predictionCol="prediction")
RMSE: 0.206
MSE: 0.042
MAE: 0.165
r2: 0.803

El modelo predictivo resulta en r2 0.803 lo que indica que se puede utilizar para hacer predicciones para años futuros.

In [79]:
# Obteniendo la fórmula de regresión lineal
modelo = model4.stages[-1]
print("params", modelo)
print("Coefficients: %s" % str(modelo.coefficients))
print("Intercept: %s" % str(modelo.intercept))
𝛼4 = modelo.intercept
𝛽4_1 = modelo.coefficients[0]
𝛽4_2 = modelo.coefficients[1]
params LinearRegression_78abfd8e4e5a
Coefficients: [0.010794441491599995,0.23008227631800884]
Intercept: -2.63445290567332

$ y = \alpha + \beta X_i \\ Donde: \beta = [0.0109, 0.2289]; X = [[x_{1,1},x_{1,2}], ... ,[x_{i,1},x_{i,2}]] \\ y = -2.63 -0.0108 X_1 + 0.2301 X_2 $

In [80]:
# usando las fórumulas para obtener predicciones nuevas para los siguientes años de 1850 a 2050
def twoFeaturesLrPredictionsByYears(intercept, coeff, meanAvf, ini=1850, fin=2051):
    predicciones = []
    print(coeff)
    for year in range(ini, fin):
        predicciones.append([year, intercept + year*coeff[0] + meanAvf*coeff[1]])
    return predicciones

meanAvtu = ndfe.approxQuantile("avg(AverageTemperatureUncertainty)", [0.5], 0.25)[0]
df_predictions3 = pd.DataFrame(data=twoFeaturesLrPredictionsByYears(𝛼3, [𝛽3_1, 𝛽3_2], meanAvtu), \
                               columns=["dt", "AverageTemperature"])
df_predictions4 = pd.DataFrame(data=twoFeaturesLrPredictionsByYears(𝛼4, [𝛽4_1, 𝛽4_2], meanAvtu), \
                               columns=["dt", "AverageTemperature"])
#print(df_predictions3.count())
df_predictions3.head()
[0.008813582768108213, -0.2874945103427946]
[0.010794441491599995, 0.23008227631800884]
Out[80]:
dt AverageTemperature
0 1850 7.653703
1 1851 7.662516
2 1852 7.671330
3 1853 7.680144
4 1854 7.688957
In [81]:
df_predictions4.head()
Out[81]:
dt AverageTemperature
0 1850 17.826125
1 1851 17.836920
2 1852 17.847714
3 1853 17.858509
4 1854 17.869303
In [82]:
df_ndfeM = ndfeM.toPandas()
df_ndfem = ndfem.toPandas()
In [83]:
data = [go.Scatter(
            x=df_years["dt"],
            y=df_years['avg(AverageTemperature)'],
            name="Valor real", mode="markers"),
        go.Scatter(
            x=df_ndfeM["dt"],
            y=df_ndfeM['avg(AverageTemperature)'],
            name="Ciudades con mayor altitud", mode="markers"),
        go.Scatter(
            x=df_ndfem["dt"],
            y=df_ndfem['avg(AverageTemperature)'],
            name="Ciudades con menor altitud", mode="markers"),
        go.Scatter(
            x=df_predictions3["dt"],
            y=df_predictions3['AverageTemperature'],
            name="Predicción 3 (sobre las 20 ciudades con mayor altitud)"),
        go.Scatter(
            x=df_predictions4["dt"],
            y=df_predictions4['AverageTemperature'],
            name="Predicción 4 (sobre las 20 ciudades con menor altitud)")
       ]

plotly.offline.iplot({
    "data": data,
    "layout": go.Layout(title="Predicción de temperatura Promedio Global por año (C°)", \
                        legend_orientation="h"),
})

Conclusión tercer y cuarto modelo.- La gráfica muestra que la temperatura promedio en las ciudades con mayor y menor altitud se incrementa, sin embargo podemos obtener el dato de la variación de temperatura según si está en el grupo de mayores o menores.

Para ello compararemos las pendientes de las líneas de predicción.

$ m = \frac{y_2 - y_1}{x_2 - x_1} $

Tomando puntos cualquiera de ambas rectas:

$ m_{M} = \frac{7.6977 - 7.6537}{1855 - 1850} = 0.0088 \\ m_{m} = \frac{17.8801 - 17.8261}{1855 - 1850} = 0.01080 $

Resultando en que la pendiente $m_{M}$ es 0.00199 más pequeña que $m_{m}$, lo que muestra que la temperatura en ciudades con menor altitud se incrementa ligeramente más que en las ciudades con mayor altitud en metros sobre el nivel del mar.

Conclusión sobre altitud sobre el nivel del mar y variación de temperatura promedio a nivel global

Usando la técnica de regresión lineal con un ajuste mayor a 0.64 y haciendo predicciones, se nota que la diferencia en el incremento de temperatura tomando en cuenta las 20 ciudades con mayor altitud y las 20 ciudades con menor altitud en el mundo es pequeña, resultando en una pendiente en el incremento de temperatura de 0.00199 entre ambas, luego:

$ m_{M} = 0.0088 \\ m_{m} = 0.0108 $

Entonces:

$ 0.01080 > 0.0088 \rightarrow m_{m} > m_{M} $

Al no cumplirse $m_{m}$ < $m_{M}$ no se puede concluir que la hipótesis H0 sea verdadera, por tanto que una ciudad esté a mayor altitud no implica que esta tendrá un mayor incremento de temperatura.